#!/usr/bin/env bash

is_a_function()
{
  \typeset -f $1 >/dev/null 2>&1 || return $?
}

# Functions RVM is built on
# __rvm_string_match <value> <string|glob>
if
  [[ -n "${ZSH_VERSION:-}" ]]
then
  __rvm_string_match()
  {
    \typeset _string _search
    _string="$1"
    shift
    while (( $# ))
    do
      _search="$1"
      _search="${_search// /[[:space:]]}"
      _search="${_search//\#/\#}"
      eval "\
      case \"\${_string}\" in\
        ($_search) return 0 ;;\
      esac\
      "
      shift
    done
    return 1
  }
else
  __rvm_string_match()
  {
    \typeset _string
    _string="$1"
    shift
    while (( $# ))
    do
      case "${_string}" in
        (${1// /[[:space:]]}) return 0 ;;
      esac
      shift
    done
    return 1
  }
fi

__rvm_array_contains()
{
  \typeset _search _iterator
  _search="$1"
  shift
  for _iterator
  do
    case "${_iterator}" in
      (${_search}) return 0 ;;
    esac
  done
  return 1
}

__rvm_array_add_or_update()
{
  \typeset _array_name _variable _separator _value _local_value
  \typeset -a _array_value_old _array_value_new

  _array_name="$1"
  _variable="$2"
  _separator="$3"
  _value="${4##${_separator}}"
  _array_value_new=()
  eval "_array_value_old=( \"\${${_array_name}[@]}\" )"

  case " ${_array_value_old[*]} " in
    (*[[:space:]]${_variable}*)
      for _local_value in "${_array_value_old[@]}"
      do
        case "${_local_value}" in
          (${_variable}*)
            _array_value_new+=( "${_local_value}${_separator}${_value}" )
            ;;
          (*)
            _array_value_new+=( "${_local_value}" )
            ;;
        esac
      done
      ;;
    (*)
      _array_value_new=( "${_array_value_old[@]}" "${_variable}${_value}" )
      ;;
  esac

  eval "${_array_name}=( \"\${_array_value_new[@]}\" )"
}

__rvm_array_prepend_or_ignore()
{
  \typeset _array_name _variable _separator _value _prefix _local_value
  \typeset -a _array_value_old _array_value_new

  _array_name="$1"
  _variable="$2"
  _separator="$3"
  _value="$4"
  _prefix="$5"
  _array_value_new=()
  eval "_array_value_old=( \"\${${_array_name}[@]}\" )"

  case " ${_array_value_old[*]} " in
    (*[[:space:]]${_variable}*)
      for _local_value in "${_array_value_old[@]}"
      do
        case "${_local_value}" in
          (${_variable}*${_prefix}*)
            rvm_debug "__rvm_array_prepend_or_ignore ${_array_name} ${_local_value}"
            _array_value_new+=( "${_local_value}" )
            ;;
          (${_variable}*)
            rvm_debug "__rvm_array_prepend_or_ignore ${_array_name} ${_variable}\"${_value}${_separator}${_local_value#${_variable}}\""
            _array_value_new+=( "${_variable}${_value}${_separator}${_local_value#${_variable}}" )
            ;;
          (*)
            _array_value_new+=( "${_local_value}" )
            ;;
        esac
      done
      eval "${_array_name}=( \"\${_array_value_new[@]}\" )"
      ;;
  esac
}

# Drop in replacement for sed -i compatible with OpenBSD
# Assumes that filename is the first argument, all others are passed onto sed
__rvm_sed_i()
{
  \typeset _filename _executable _user
  [[ -n "${1:-}" ]] || {
    rvm_debug "no file given for __rvm_sed_i"
    return 0
  }
  _filename="$1"
  shift

  if [[ -x "${_filename}" ]]
  then _executable=true
  fi
  _user="$( __rvm_statf "%u:%g" "%u:%g" "${_filename}" )"

  {
    __rvm_sed "$@" < "${_filename}" > "${_filename}.new" &&
    \command \mv -f "${_filename}.new" "${_filename}"
  } 2>&1 | rvm_debug_stream

  if [[ -n "${_executable:-}" && ! -x "${_filename}" ]]
  then chmod +x "${_filename}"
  fi
  if [[ "$_user" != "$( __rvm_statf "%u:%g" "%u:%g" "${_filename}" )" ]]
  then chown "$_user" "${_filename}"
  fi
}

# Drop in cd which _doesnt't_ respect cdpath
__rvm_cd()
{
    \typeset old_cdpath ret
    ret=0
    old_cdpath="${CDPATH}"
    CDPATH="."
    chpwd_functions="" builtin cd "$@" || ret=$?
    CDPATH="${old_cdpath}"
    return $ret
}

__rvm_setup_utils_functions()
{
  \typeset gnu_tools_path gnu_prefix gnu_util
  \typeset -a gnu_utils gnu_missing
  gnu_utils=( awk cp date find sed tail tar xargs )
  gnu_missing=()

  if is_a_function __rvm_setup_utils_functions_${_system_name}
  then __rvm_setup_utils_functions_${_system_name} "$@" || return $?
  else __rvm_setup_utils_functions_Other "$@" || return $?
  fi
}

__rvm_setup_utils_functions_Solaris()
{
  case "${_system_version}" in
    (10)
      gnu_tools_path=/opt/csw/bin
      gnu_prefix="g"
      ;;
    (11)
      gnu_tools_path=/usr/gnu/bin
      gnu_prefix=""
      ;;
  esac

  if [[ -x $gnu_tools_path/${gnu_prefix}grep ]]
  then eval "__rvm_grep() { GREP_OPTIONS=\"\" $gnu_tools_path/${gnu_prefix}grep \"\$@\" || return \$?; }"
  else gnu_missing+=( ${gnu_prefix}grep )
  fi

  if [[ "${_system_name}" == "OpenIndiana" || "${_system_version}" == "11" ]]
  then __rvm_stat() { \command \stat "$@" || return $?; }
  elif [[ -x $gnu_tools_path/${gnu_prefix}stat ]]
  then eval "__rvm_stat() { $gnu_tools_path/${gnu_prefix}stat \"\$@\" || return \$?; }"
  else gnu_missing+=( ${gnu_prefix}stat )
  fi

  if [[ "${_system_name}" == "SmartOS" ]]
  then __rvm_which() { \command \which "$@" || return $?; }
  elif [[ -x $gnu_tools_path/${gnu_prefix}which ]]
  then eval "__rvm_which() { $gnu_tools_path/${gnu_prefix}which \"\$@\" || return \$?; }"
  else gnu_missing+=( ${gnu_prefix}which )
  fi

  for gnu_util in "${gnu_utils[@]}"
  do
    if [[ -x $gnu_tools_path/$gnu_prefix$gnu_util ]]
    then eval "__rvm_$gnu_util() { $gnu_tools_path/$gnu_prefix$gnu_util \"\$@\" || return \$?; }"
    else gnu_missing+=( $gnu_prefix$gnu_util )
    fi
  done

  if
    (( ${#gnu_missing[@]} ))
  then
    rvm_error "ERROR: Missing GNU tools: ${gnu_missing[@]}. Make sure they are installed in '$gnu_tools_path/' before using RVM!"
    if [[ "${_system_name} ${_system_version}" == "Solaris 10" ]]
    then rvm_error "You might want to look at OpenCSW project to install the above mentioned tools (https://www.opencsw.org/about)"
    fi
    exit 200
  fi
}

__rvm_setup_utils_functions_OSX()
{
  if
    [[ -x /usr/bin/stat ]]
  then
    __rvm_stat() { /usr/bin/stat "$@" || return $?; }
  else
    rvm_error "ERROR: Missing (executable) /usr/bin/stat. Falling back to '\\\\command \\\\stat' which might be something else."
    __rvm_stat() { \command \stat "$@" || return $?; }
  fi
  __rvm_setup_utils_functions_common
}

__rvm_setup_utils_functions_Other()
{
  __rvm_stat() { \command \stat "$@" || return $?; }
  __rvm_setup_utils_functions_common
}

__rvm_setup_utils_functions_common()
{
  __rvm_grep() { GREP_OPTIONS="" \command \grep "$@" || return $?; }

  if \command \which --skip-alias --skip-functions which >/dev/null 2>&1
  then __rvm_which() { \command \which --skip-alias --skip-functions "$@" || return $?; }
  elif \command \which whence >/dev/null 2>&1 && \command \whence whence >/dev/null 2>&1
  then __rvm_which() { \command \whence -p "$@" || return $?; }
  elif \command \which which >/dev/null 2>&1
  then __rvm_which() { \command \which "$@" || return $?; }
  elif \which which >/dev/null 2>&1
  then __rvm_which() { \which "$@" || return $?; }
  else
    \typeset __result=$?
    rvm_error "ERROR: Missing proper 'which' command. Make sure it is installed before using RVM!"
    return ${__result}
  fi

  for gnu_util in "${gnu_utils[@]}"
  do eval "__rvm_$gnu_util() { \\$gnu_util \"\$@\" || return \$?; }"
  done
}

__rvm_setup_utils_functions || return $?

# detect system after setting up __rvm_sed and before setting up __rvm_statf
source "${rvm_scripts_path}/functions/db"
source "${rvm_scripts_path}/functions/detect/system"

__rvm_setup_statf_function()
{
  if
    [[ "${_system_type}" == Darwin || "${_system_type}" == BSD ]]
  then
    __rvm_statf()
    {
      __rvm_stat -f "$2" "$3"
    }
  else
    __rvm_statf()
    {
      __rvm_stat -c "$1" "$3"
    }
  fi
}

__rvm_setup_statf_function || return $?


__rvm_setup_sudo_function()
{
  if is_a_function __rvm_setup_sudo_function_${_system_name}
  then __rvm_setup_sudo_function_${_system_name} "$@" || return $?
  else __rvm_setup_sudo_function_Other "$@" || return $?
  fi
}

__rvm_setup_sudo_function_PCLinuxOS()
{
  __rvm_sudo()
  {
    if
      [[ "$1" == "-p" ]]
    then
      rvm_printf_to_stderr "${2//%p/[root]/}"
      shift 2
    fi
    su -c "$*"
  }
}

__rvm_setup_sudo_function_Solaris()
{
  if
    [[ -x /opt/csw/bin/sudo ]]
  then
    __rvm_sudo()
    {
      /opt/csw/bin/sudo "$@"
    }
  elif
    [[ -x /usr/bin/sudo ]]
  then
    __rvm_sudo()
    {
      /usr/bin/sudo "$@"
    }
  else
    rvm_debug "Warning: No '/opt/csw/bin/sudo' found."
  fi
}

__rvm_setup_sudo_function_Other()
{
  if
    __rvm_which sudo >/dev/null 2>&1
  then
    __rvm_sudo()
    {
      \command \sudo "$@"
    }
  else
    rvm_debug "Warning: No 'sudo' found."
  fi
}

__rvm_setup_sudo_function || return $?

# Utils that are not needed for RVM installation
# but have non-standard paths in Solaris 10
other_utils=( ant automake autoreconf libtoolize make mount patch readlink )

if
  [[ "${_system_name} ${_system_version}" == "Solaris 10" ]]
then
  __rvm_ant()        { /usr/sfw/bin/ant        "$@" || return $?; }
  __rvm_automake()   { /opt/csw/bin/automake   "$@" || return $?; }
  __rvm_autoreconf() { /opt/csw/bin/autoreconf "$@" || return $?; }
  __rvm_libtoolize() { /opt/csw/bin/libtoolize "$@" || return $?; }
  __rvm_make()       { /opt/csw/bin/gmake      "$@" || return $?; }
  __rvm_mount()      { /sbin/mount             "$@" || return $?; }
  __rvm_patch()      { /opt/csw/bin/gpatch     "$@" || return $?; }
  __rvm_readlink()   { /opt/csw/bin/greadlink  "$@" || return $?; }
else
  for other_util in "${other_utils[@]}"
  do eval "__rvm_$other_util() { \\$other_util \"\$@\" || return \$?; }"
  done
fi
unset other_util other_utils

__rvm_readlink_deep()
{
  eval "
    while [[ -n \"\${$1}\" && -L \"\${$1}\" ]]
    do $1=\"\$(__rvm_readlink \"\${$1}\")\"
    done
  "
}

## duplication marker 32fosjfjsznkjneuera48jae
__rvm_curl_output_control()
{
  if
    (( ${rvm_quiet_curl_flag:-0} == 1 ))
  then
    __flags+=( "--silent" "--show-error" )
  elif
    [[ " $*" == *" -s"* || " $*" == *" --silent"* ]]
  then
    # make sure --show-error is used with --silent
    [[ " $*" == *" -S"* || " $*" == *" -sS"* || " $*" == *" --show-error"* ]] ||
    {
      __flags+=( "--show-error" )
    }
  fi
}

## duplication marker 32fosjfjsznkjneuera48jae
# -S is automatically added to -s
__rvm_curl()
(
  \typeset curl_path
  if
    [[ "${_system_name} ${_system_version}" == "Solaris 10" ]] &&
    ! __rvm_which curl >/dev/null 2>&1
  then
    curl_path=/opt/csw/bin/
  else
    curl_path=""
  fi
  __rvm_which ${curl_path}curl >/dev/null 2>&1 ||
  {
    rvm_error "RVM requires 'curl'. Install 'curl' first and try again."
    return 200
  }

  \typeset -a __flags
  __flags=( --fail --location )

  # allow overriding default 30 minutes for download, but should be plenty of time
  if [[ -n "${rvm_curl_flags[*]}" ]]
  then __flags+=( "${rvm_curl_flags[@]}" )
  else __flags+=( --max-redirs 10 --max-time 1800 )
  fi

  [[ "$*" == *"--max-time"* ]] ||
  [[ "$*" == *"--connect-timeout"* ]] ||
  [[ "${__flags[*]}" == *"--connect-timeout"* ]] ||
    __flags+=( --connect-timeout 30 --retry-delay 2 --retry 3 )

  if [[ -n "${rvm_proxy:-}" ]]
  then __flags+=( --proxy "${rvm_proxy:-}" )
  fi

  __rvm_curl_output_control

  unset curl
  __rvm_debug_command ${curl_path}curl "${__flags[@]}" "$@" || return $?
)

is_parent_of()
{
  \typeset name pid ppid pname
  name=$1
  pid=$2
  while [[ -n "$pid" && "$pid" != "0" ]]
  do
    case "`uname`" in
      (SunOS)
        read ppid pname <<<"$(\command \ps -p $pid -o ppid= -o comm=)"
        ;;
      (*)
        read ppid pname <<<"$(\command \ps -p $pid -o ppid= -o ucomm=)"
        ;;
    esac
    if [[ -n "$ppid" && -n "$pname" ]]
    then
      if [[ "$pname" == "$name" ]]
      then
        echo $pid
        return 0
      else
        pid=$ppid
      fi
    else
      break
    fi
  done
  return 1
}

__rvm_string_includes()
{
  \typeset __search __text="$1"
  shift
  for __search in "$@"
  do
    if [[ " ${__text} " == *" ${__search} "* ]]
    then return 0
    fi
  done
  return 1
}

__function_on_stack()
{
  __rvm_string_includes "${FUNCNAME[*]}" "$@" || return $?
}

# read lines from file / stdin(-)
__rvm_read_lines()
{
  \typeset IFS
  # NEW LINE, BE CAREFUL
  IFS="
"
  if [[ "${2:--}" == "-" ]]
  then eval "$1=( \$( \command \cat - ) )"
  else eval "$1=( \$( \command \cat \"\${2:--}\" ) )"
  fi
}

__setup_lang_fallback()
{
  if
    [[ -z "${LANG:-}" ]]
  then
    LANG="$(
      {
        locale -a | __rvm_grep "^en_US.utf8" ||
        locale -a | __rvm_grep "^en_US" ||
        locale -a | __rvm_grep "^en" ||
        locale -a
      } 2>/dev/null | \command \head -n 1
    )"
    : LANG=${LANG:=en_US.utf-8}
    export LANG
    rvm_warn "\$LANG was empty, setting up LANG=$LANG, if it fails again try setting LANG to something sensible and try again."
  fi
}

__rvm_ruby_config_save()
{
  \typeset ruby_path
  ruby_path="${1:-$rvm_ruby_home/bin/ruby}"
  case "$ruby_path" in
    (*/mruby*)
      __rvm_ruby_config_save_mruby "${2:-${ruby_path%%/bin/ruby}/config}"
      ;;
    (*)
      __rvm_ruby_config_save_generic "$2"
      ;;
  esac
}

__rvm_ruby_config_save_mruby()
{
  echo "target_cpu=\"$_system_arch\"" > "$1"
}

__rvm_ruby_config_save_generic()
{
  \typeset config_path default_config_path
  default_config_path="#{RbConfig::CONFIG[\"prefix\"]}/config"
  config_path="${1:-$default_config_path}"
  "$ruby_path" -rrbconfig -e '\
    File.open("'"$config_path"'","w") { |file|
      RbConfig::CONFIG.sort.each{|key,value|
        file.write("#{key.gsub(/\.|-/,"_")}=\"#{value.to_s.gsub("$","\\$")}\"\n")
      }
    }
  ' >/dev/null 2>&1
}

__rvm_record_ruby_configs()
{
  \typeset __dir
  for __dir in "$rvm_path/rubies/"*
  do
    if
      [[ ! -L "${__dir}" && ! -s "${__dir}/config" && -x "${__dir}/bin/ruby" ]]
    then
      __rvm_ruby_config_save "${__dir}/bin/ruby" "${__dir}/config" ||
      {
        \typeset string="${__dir##*/}"
        rvm_error "    Can not save config data for ruby: '${string}', most likely it is broken installation and you can:
    - try fix it: 'rvm reinstall ${string}', OR:
    - remove  it: 'rvm uninstall ${string} --gems'"
      }
    fi
  done
}

__rvm_ls() { \command \ls "$@" || return $?; }
